#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <malloc.h>
#include <time.h>
#include <stdlib.h>
#pragma comment (lib,"Winmm.lib")

void gotoxy(int x, int y);//设置光标
void background();//背景生成
void setcolour(int a);//设置颜色
void startup();//初始化
void hidecursor();//隐藏光标
void startfood();//初始创建食物
void startsnake();//初始创建小蛇
void snakemove(int, int);//小蛇移动
int checksnake(int);//小蛇碰撞检测
void snakedie();//小蛇死亡
void showing();//输出最新的show
void screenRefresh(int);//屏幕刷新
void newfood();//创建新食物
void updategoal();//更新得分
int movedire(int, int);//获取小蛇的移动方向
int snakelength = 3;//小蛇长度
int snakehead = 2;//蛇头
int snaketail = 0;//蛇尾
int High = 40, Width = 40;//定义最大行数，列数

//结构体保存各个事物的属性

struct map
{
	int colour;
	int kind;
	const char* attribute;
}

show[40][40], //展示地图
wall = { 0x8C,1,"■" },//墙体
activearea = { 0x7A,2,"□" },//小蛇活动区域
food = { 0x7C,3,"※" },//食物
snake = { 0x4A,4,"●" };//小蛇蛇体的属性

struct SnakeMap
{
	int x;
	int y;
}SnakeSite[100], FoodSite;

/***************************************

				主程序

****************************************/

int main()
{
	int olddirection = 'w'; //初始键盘信号
	int newdirection = 0;//获取键盘信号

	startup();//初始化

	gotoxy(60, 0);
	setcolour(0x80);
	printf("\n得分：");
	printf("%d\n", snakelength - 3);
	printf("请切换为英文输入法\n");
	printf("W A S D键分别表示：上 左 下 右\n");
	printf("c语言课程设计小组13");

	while (1)
	{
		
		if (_kbhit())		 //检测缓冲区中是否有数据
		{
			newdirection = tolower(_getch());  //将缓冲区中的数据以字符的形式读出
		}
		newdirection = movedire(olddirection, newdirection);
		screenRefresh(newdirection);
		Sleep(250);
	}
	return 0;
}

/*******************************

	初始化生成show结构体数组

*******************************/

void startup()
{
	                                      //设置窗口大小
	system("mode con:cols=100 lines=45");//隐藏光标
	hidecursor();	//生成背景图
	background();//创建初始食物
	startfood();//创建初始小蛇蛇体
	startsnake();	//显示
	showing();
	mciSendString("open D:\\microsoft\\bj.mp3 alias bkmusic", NULL, 0, NULL);
	mciSendString("play bkmusic repeat", NULL, 0, NULL);

}

//更新得分

void updategoal()
{
	setcolour(0xF0);
	gotoxy(60, 0);
	printf("\n得分：%d", snakelength - 3);
	mciSendString("open D:\\microsoft\\jinshi.mp3 alias gxmusic", NULL, 0, NULL);
	mciSendString("play gxmusic ", NULL, 0, NULL);
}

//碰撞检测

int checksnake(int newdirection)
{
	switch (newdirection)
	{
		case 'w':
			if ((show[SnakeSite[snakehead].x - 1][SnakeSite[snakehead].y].kind) == 1)
			{
			snakedie();
			return 0;
			}
		else if ((show[SnakeSite[snakehead].x - 1][SnakeSite[snakehead].y].kind) == 4)
		{
			snakedie();
			return 0;
		}

		else if ((show[SnakeSite[snakehead].x - 1][SnakeSite[snakehead].y].kind) == 3)
		{
			return 1;
		}
		else
		{
			return 2;
		}
		break;
	case 's':
		if ((show[SnakeSite[snakehead].x + 1][SnakeSite[snakehead].y].kind) == 1)
		{
			snakedie();
			return 0;
		}
		else if ((show[SnakeSite[snakehead].x + 1][SnakeSite[snakehead].y].kind) == 4)
		{
			snakedie();
			return 0;
		}
		else if ((show[SnakeSite[snakehead].x + 1][SnakeSite[snakehead].y].kind) == 3)
		{
			return 1;
		}

		else
		{
			return 2;
		}
		break;
	case 'a':
		if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y - 1].kind) == 1)
		{
			snakedie();
			return 0;
		}
		else if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y - 1].kind) == 4)
		{
			snakedie();
			return 0;
		}
		else if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y - 1].kind) == 3)
		{
			return 1;
		}
		else
		{
			return 2;
		}
		break;
	case 'd':
		if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y + 1].kind) == 1)
		{
			snakedie();
			return 0;
		}
		else if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y + 1].kind) == 4)
		{
			snakedie();
			return 0;
		}

		else if ((show[SnakeSite[snakehead].x][SnakeSite[snakehead].y + 1].kind) == 3)
		{
			return 1;
		}
		else
		{
			return 2;
		}
		break;
	}
}

//创建新食物

void newfood()
{
	srand((unsigned)time(NULL));
	FoodSite.x = rand() % 38 + 1;
	FoodSite.y = rand() % 38 + 1;
}

//刷新屏幕

void screenRefresh(int newdirection)
{
	int re = 0;
	int i = 0;
	re = checksnake(newdirection);
	snakemove(newdirection, re);
	background();
	show[FoodSite.x][FoodSite.y] = food;
	for (i = 0; i <= snakehead; i++)
	{
		if (i == snakehead)
		{
			show[SnakeSite[i].x][SnakeSite[i].y] = snake;
			show[SnakeSite[i].x][SnakeSite[i].y].colour = 0x75;
		}
		else
		{
			show[SnakeSite[i].x][SnakeSite[i].y] = snake;
		}
	}
	
	showing();
	if (re == 1)
	{
		snakelength++;
		updategoal();
		newfood();
	}
}

/*********************************************

				获取最新的方向

**********************************************/

int movedire(int olddirection, int newdirection)
{
	if (newdirection == 'w' || newdirection == 'a' || newdirection == 's' || newdirection == 'd')
	{
		return newdirection;
	}
	else
	{
		return olddirection;
	}
}

/**********************************

		  展示最新的show

*********************************/

void showing()
{
	int i, j;
	for (i = 0; i < High; i++)
	{
		for (j = 0; j < Width; j++)
		{
			gotoxy(i, j);
			setcolour(show[i][j].colour);
			printf("%s", show[i][j].attribute);
		}
	}
}

/******************************************

			小蛇死亡

/*******************************************/

void snakedie()
{
	mciSendString("open D:\\microsoft\\sw.mp3 alias swmusic", NULL, 0, NULL);
	mciSendString("play swmusic ", NULL, 0, NULL);
	gotoxy(20, 5);
	printf("Game over! 按任意键结束游戏！");
	Sleep(5000);
	_getch();
	exit(0);
}

//小蛇移动
void snakemove(int newdirection, int re)
{
	int i = 0;
	switch (newdirection)
	{
	case 'w':
		for (i = 0; i < snakehead; i++)
		{
			SnakeSite[i].x = SnakeSite[i + 1].x;
			SnakeSite[i].y = SnakeSite[i + 1].y;
		}
		SnakeSite[snakehead].x --;
		if (re == 1)
		{
			snakehead += 1;
			SnakeSite[snakehead].x = SnakeSite[snakehead - 1].x - 1;
			SnakeSite[snakehead].y = SnakeSite[snakehead - 1].y;
		}
		break;
	case 's':
		for (i = 0; i < snakehead; i++) {
			SnakeSite[i].x = SnakeSite[i + 1].x;
			SnakeSite[i].y = SnakeSite[i + 1].y;
		}
		SnakeSite[snakehead].x += 1;
		if (re == 1)
		{
			snakehead += 1;
			SnakeSite[snakehead].x = SnakeSite[snakehead - 1].x + 1;
			SnakeSite[snakehead].y = SnakeSite[snakehead - 1].y;
		}
		break;
	case 'a':
		for (i = 0; i < snakehead; i++) {
			SnakeSite[i].x = SnakeSite[i + 1].x;
			SnakeSite[i].y = SnakeSite[i + 1].y;
		}
		SnakeSite[snakehead].y -= 1;
		if (re == 1)
		{
			snakehead += 1;
			SnakeSite[snakehead].x = SnakeSite[snakehead - 1].x;
			SnakeSite[snakehead].y = SnakeSite[snakehead - 1].y - 1;
		}
		break;
	case 'd':
		for (i = 0; i < snakehead; i++) {
			SnakeSite[i].x = SnakeSite[i + 1].x;
			SnakeSite[i].y = SnakeSite[i + 1].y;

		}
		SnakeSite[snakehead].y += 1;
		if (re == 1)
		{
			snakehead += 1;
			SnakeSite[snakehead].x = SnakeSite[snakehead - 1].x;
			SnakeSite[snakehead].y = SnakeSite[snakehead - 1].y + 1;
		}
		break;
	}
}

//初始食物

void startfood()
{
	FoodSite.x = 5;
	FoodSite.y = 10;
	show[5][10] = food;
}

//初始小蛇

void startsnake()
{
	SnakeSite[0].x = 35;
	SnakeSite[0].y = 13;
	SnakeSite[1].x = 35;
	SnakeSite[1].y = 12;
	SnakeSite[2].x = 35;
	SnakeSite[2].y = 11;
	show[35][11] = snake;
	show[35][11].colour = 0x75;
	show[35][12] = snake;
	show[35][13] = snake;
}

/**************************************

			生成背景图

**************************************/

void background()
{
	int i, j;
	for (i = 0; i < High; i++)
	{
		for (j = 0; j < Width; j++)
		{
			
			if (j == 0 || j == Width - 1 || i == 0 || i == High - 1)
			{
				show[i][j] = wall;
			}
			else
			{
				show[i][j] = activearea;
			}
		}
	}
}

/********************************

		定义光标位置

*********************************/

void gotoxy(int x, int y)

{
	COORD coord;
	coord.X = y * 2;  //第3列
	coord.Y = x;  //第3行
	//获取控制台缓冲区句柄
	HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置光标位置
	SetConsoleCursorPosition(ConsoleHandle, coord);

}

//设置种类的颜色

void setcolour(int a)
{
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hConsole, a);
}
//隐藏光标

void hidecursor()
{
	CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
